package com.example.demo.config;

import com.example.demo.service.UserDatailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.StandardPasswordEncoder;

import javax.sql.DataSource;


/*
   添加spring security安全框架到pom
   所有的http都需要认证
   不需要特定的角色和权限
   没有登录页面
   认证过程是通过Http basic对话认证框实现的
   系统只有一个用户User
   -------------------------------------------
   通过登录页面提示用户进行认证，而不是HTTP basic
   提供多个用户，并提供一个注册页面
   对不同的路径，执行不同的安全规则
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

//    @Autowired
//    private DataSource dataSource;

    @Autowired
    private UserDetailsService userDetailsService;

 /*
  重写方法进行用户储存
  spring 提供了 基于内存的储存
  基于JDBC的储存
  基于LDAP作为后端的用户储存 Lightweight Directory Access Protocol 轻量级目录访问协议
  自定义用户详情页
  */

    // 基于内存储存用户 不能很好的编辑用户
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth                                   // 使用构造者build接口来构建细节
//                .inMemoryAuthentication()      // 指定用户信息
//                .withUser("buzz")    // 配置用户
//                .password("infinity")
//                .authorities("ROLE_USER")
//                .and()
//                .withUser("woody")
//                .password("bullseye")
//                .authorities("ROLE_USER");
//    }
//
    //基于JDBC储存， 必须设置一个dataSource，才能让其访问数据库
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//       auth
//               .jdbcAuthentication()
//               .dataSource(dataSource);
//    }

    // 用户自定义查询
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth
//                .jdbcAuthentication()
//                .dataSource(dataSource)
//                .usersByUsernameQuery("select username,password,enable from Users where username=?")
//                .authoritiesByUsernameQuery("select username,authority from UserAuthorities where username = ?")
//                .passwordEncoder(new StandardPasswordEncoder("53cr3t")); //密码加密
//    }


    // 基于LDAP 默认情况下spring的LDAP认证假设LADP服务器监听本机的33389端口，但是你的LDAP服务器如果在别的机器上可以使用contextSource（）

//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth
//                .ldapAuthentication()
//                .userSearchBase("ou=people")    //查找用户提供了基础查询 声明用户应在名为people的组织单元下搜素
//                .userSearchFilter("{uid={0}}")
//                .groupSearchBase("ou=groups")   // 查找组提供了基本查询
//                .groupSearchFilter("member={0}")
//                .passwordCompare()                 //密码对比 在LDAP的服务器上
//                .passwordEncoder(new BCryptPasswordEncoder())   // 加密
//                .passwordAttribute("passcode");                 //如果密码保存在不同的属性上，可以通过这个方法来申明密码属性;
//    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {

        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(encoder());// encoder()方法有@bean注解，
        // 他将用来在Spring应用到上下文申明PasswordEncoder，对于encoder的任何调用，都会被拦截，并且返回应用上下文中的bean实例


    }

    // 这册一个PasswordEncoder到容器中
    @Bean
    public PasswordEncoder encoder() {
        return new StandardPasswordEncoder("53cr3t");
    }

    /*
       配置web级别如何处理安全性
       1 请求某个请求提供服务之前，需要满足特定的条件
       2 配置自定义的登录项
       3 支持用户退出应用
       4 预防跨站请求伪造
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/design", "/order")
                .hasRole("USER")
                .antMatchers("/", "/**")
//                .permitAll();
                .access("permitAll")
                .and()
                .formLogin()
                .loginPage("/login")        //告诉Spring自定义的登录页面路径在哪
                .defaultSuccessUrl("/design") //登录成功访问design
                .and()
                .logout()
                .logoutSuccessUrl("/"); //可以指定退出去往那个界面

        //对于design ，order请求只有User才能访问，其他的请求均可以访问。两条安全规则顺序重要，不能颠倒
    }
}
